package com.ums.upos.service;

import android.os.Bundle;
import android.os.RemoteException;
import com.nexgo.common.ByteUtils;
import com.nexgo.oaf.apiv3.SdkResult;
import com.nexgo.oaf.apiv3.card.cpu.CPUCardHandler;
import com.nexgo.oaf.apiv3.card.mifare.M1CardHandler;
import com.nexgo.oaf.apiv3.device.reader.CardInfoEntity;
import com.nexgo.oaf.apiv3.device.reader.CardReader;
import com.nexgo.oaf.apiv3.device.reader.CardSlotTypeEnum;
import com.nexgo.oaf.apiv3.device.reader.OnCardInfoListener;
import com.nexgo.oaf.apiv3.device.reader.RfCardTypeEnum;
import com.nexgo.oaf.apiv3.device.reader.TypeAInfoEntity;
import com.nexgo.oaf.apiv3.device.reader.TypeBInfoEntity;
import com.ums.upos.GlobalDataHolder;
import com.ums.upos.uapi.ServiceResult;
import com.ums.upos.uapi.device.reader.icc.ICCSearchResult;
import com.ums.upos.uapi.device.reader.icc.IccCardReader;
import com.ums.upos.uapi.device.reader.icc.IccCardType;
import com.ums.upos.uapi.device.reader.icc.OnSearchIccCardListener;
import com.ums.upos.util.CardUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

/**
 * Created by xiaox on 15-10-7.
 */
public class IccReaderBinder extends IccCardReader.Stub {
    private final String TAG = "IccReaderService";
    private Logger log;
    private int slotNo;
    private CardReader sdkCardReader;
    private CPUCardHandler sdkCPUCardHandler;
    private IccReaderBinder mIccCardReader;

    IccReaderBinder(int slotNo) {
        this.slotNo = slotNo;
        log = LoggerFactory.getLogger(TAG);
        sdkCardReader = GlobalDataHolder.getInstance().getDeviceEngine().getCardReader();
        mIccCardReader = this;
    }

    @Override
    public int searchCard(final OnSearchIccCardListener listener, int timeout, final String[] cardType) throws RemoteException {
        try {
            log.info("call searchCard Icc,timeout:{}");
            if (listener == null) {
                log.error("searchCard Icc param error:listener null");
                return ServiceResult.Param_In_Invalid;
            }
            if (cardType == null || cardType.length == 0) {
                listener.onSearchResult(ServiceResult.Param_In_Invalid, null);
                log.error("searchCard Icc param error:cardType null");
                return ServiceResult.Param_In_Invalid;
            }
            final List<String> list = new ArrayList<String>();
            List<String> typelist = new ArrayList<String>();
            typelist.add(IccCardType.CPUCARD);
            typelist.add(IccCardType.M1CARD);
            typelist.add(IccCardType.FELICA);
            typelist.add(IccCardType.AT24CXX);
            typelist.add(IccCardType.AT88SC102);
            typelist.add(IccCardType.AT88SC1604);
            typelist.add(IccCardType.AT88SC1608);
            typelist.add(IccCardType.SLE44X2);
            typelist.add(IccCardType.SLE44X8);

            for (String type : typelist) {
                for (String t : cardType) {
                    if (t.equals(type)) {
                        log.debug("searchCard Icc, valid cardType:{}", t);
                        list.add(type);
                    }
                }
            }

            HashSet<CardSlotTypeEnum> cardSlotTypeSet = new HashSet<>();
            cardSlotTypeSet.add(CardUtils.slotConvert(slotNo));
            int result = sdkCardReader.searchCard(cardSlotTypeSet, timeout, new OnCardInfoListener() {
                @Override
                public void onCardInfo(int retCode, CardInfoEntity cardInfoEntity) {
                    log.debug("cardInfoEntity {}", cardInfoEntity.getRfCardType());
                    log.debug("cardInfoEntity {}", cardInfoEntity.getCardExistslot());
                    try {
                        IccReaderHolder iccReaderHolder = null;
                        List<IccReaderHolder> iccReaderHolderList = GlobalDataHolder.getInstance().getIccReaderHolderList();
                        for (IccReaderHolder holder : iccReaderHolderList) {
                            if (holder.getSlotNo() == slotNo) {
                                iccReaderHolder = holder;
                                break;
                            }
                        }
                        if (iccReaderHolder == null) {
                            iccReaderHolder = new IccReaderHolder(slotNo, mIccCardReader);
                            iccReaderHolderList.add(iccReaderHolder);
                        }
                        Bundle bundle = new Bundle();
                        switch (retCode) {
                            case SdkResult.Success:
                                //mhl20171019 每次寻卡成功，回复非接默认激活关闭
                                GlobalDataHolder.getInstance().setRFActive(false);
                                for (String type : list) {
                                    switch (type) {
                                        case IccCardType.CPUCARD:
                                            CPUCardHandler cpuCardHandler = GlobalDataHolder.getInstance().getDeviceEngine().getCPUCardHandler(cardInfoEntity.getCardExistslot());
                                            boolean isOk;
                                            if (cardInfoEntity.getCardExistslot() == CardSlotTypeEnum.RF) {
                                                log.info("IccCardType {}_RF", IccCardType.CPUCARD);
                                                isOk = (cardInfoEntity.getRfCardType() == RfCardTypeEnum.TYPE_A_CPU) || (cardInfoEntity.getRfCardType() == RfCardTypeEnum.TYPE_B_CPU);
                                                //非接的要找cpu卡，返回不是的话，就跳过继续去匹配
                                                if (isOk) {
                                                    iccReaderHolder.setCardType(IccCardType.CPUCARD);
                                                    List<String> cardTypeList = Arrays.asList(cardType);
                                                    if (cardTypeList.contains(IccCardType.CPUCARD)) {
                                                        bundle.putString(ICCSearchResult.CARDTYPE, IccCardType.CPUCARD);
                                                    } else {
                                                        bundle.putString(ICCSearchResult.CARDTYPE, IccCardType.PSAM);
                                                    }
                                                    if (GlobalDataHolder.getInstance().isSupportGetRfCardInfo()) {
                                                        if (cardInfoEntity.getRfCardType() == RfCardTypeEnum.TYPE_A_CPU) {
                                                            CardSlotTypeEnum cardSlotTypeEnum = CardUtils.slotConvert(iccReaderHolder.getSlotNo());
                                                            sdkCPUCardHandler = GlobalDataHolder.getInstance().getDeviceEngine().getCPUCardHandler(cardSlotTypeEnum);
                                                            sdkCPUCardHandler.active();
                                                            //mhl20171019 更新激活状态
                                                            GlobalDataHolder.getInstance().setRFActive(true);
                                                            TypeAInfoEntity typeAInfoEntity = new TypeAInfoEntity();
                                                            log.debug("++++++++++++++ call sdkCardReader.getRfCardInfo");
                                                            sdkCardReader.getRfCardInfo(typeAInfoEntity);
                                                            log.debug("++++++++++++++ end sdkCardReader.getRfCardInfo");
                                                            int atsLen = 0;
                                                            if (typeAInfoEntity.getAts() != null)
                                                                atsLen = typeAInfoEntity.getAts().length;
                                                            byte[] cardOther = new byte[atsLen + 3];
                                                            System.arraycopy("00".getBytes(), 0, cardOther, 0, 2);
                                                            cardOther[2] = (byte) atsLen;
                                                            if (atsLen > 0)
                                                                System.arraycopy(typeAInfoEntity.getAts(), 0, cardOther, 3, typeAInfoEntity.getAts().length);
                                                            bundle.putByteArray(ICCSearchResult.CARDOTHER, cardOther);
                                                        } else {
                                                            TypeBInfoEntity typeBInfoEntity = new TypeBInfoEntity();
                                                            sdkCardReader.getRfCardInfo(typeBInfoEntity);
                                                            int atqbLen = 0;
                                                            if (typeBInfoEntity.getAtqb() != null)
                                                                atqbLen = typeBInfoEntity.getAtqb().length;
                                                            byte[] cardOther = new byte[atqbLen + 3];
                                                            System.arraycopy("00".getBytes(), 0, cardOther, 0, 2);
                                                            cardOther[2] = (byte) typeBInfoEntity.getAtqb().length;
                                                            if (atqbLen > 0)
                                                                System.arraycopy(typeBInfoEntity.getAtqb(), 0, cardOther, 3, typeBInfoEntity.getAtqb().length);
                                                            bundle.putByteArray(ICCSearchResult.CARDOTHER, cardOther);
                                                        }
                                                    }
                                                    listener.onSearchResult(ServiceResult.Success, bundle);
                                                    return;
                                                }
                                            } else {
                                                log.info("IccCardType {}", IccCardType.CPUCARD);
                                                //接触式的要找cpu卡，复位失败就给返回IccCardReader_CardInit_Error
                                                isOk = cpuCardHandler.powerOn(new byte[64]);
                                                if (isOk) {
                                                    iccReaderHolder.setCardType(IccCardType.CPUCARD);
                                                    List<String> cardTypeList = Arrays.asList(cardType);
                                                    if (cardTypeList.contains(IccCardType.CPUCARD)) {
                                                        bundle.putString(ICCSearchResult.CARDTYPE, IccCardType.CPUCARD);
                                                    } else {
                                                        bundle.putString(ICCSearchResult.CARDTYPE, IccCardType.PSAM);
                                                    }
                                                    listener.onSearchResult(ServiceResult.Success, bundle);
                                                } else {
                                                    listener.onSearchResult(ServiceResult.IccCardReader_CardInit_Error, null);
                                                }
                                                return;
                                            }
                                            break;
                                        case IccCardType.M1CARD:
                                            log.info("IccCardType {}", IccCardType.M1CARD);
                                            if (cardInfoEntity.getCardExistslot() == CardSlotTypeEnum.RF) {
                                                if (cardInfoEntity.getRfCardType() == RfCardTypeEnum.S50
                                                        || cardInfoEntity.getRfCardType() == RfCardTypeEnum.S70
                                                        || cardInfoEntity.getRfCardType() == RfCardTypeEnum.S50_PRO
                                                        || cardInfoEntity.getRfCardType() == RfCardTypeEnum.S70_PRO
                                                        || cardInfoEntity.getRfCardType() == RfCardTypeEnum.ULTRALIGHT) {
                                                    M1CardHandler m1CardHandler = GlobalDataHolder.getInstance().getDeviceEngine().getM1CardHandler();
                                                    iccReaderHolder.setCardType(IccCardType.M1CARD);
                                                    bundle.putString(ICCSearchResult.CARDTYPE, IccCardType.M1CARD);
//                                                    bundle.putByteArray(ICCSearchResult.M1SN, ByteUtils.hexString2ByteArray(m1CardHandler.readUid()));
                                                    bundle.putByteArray(ICCSearchResult.M1SN, ByteUtils.string2ASCIIByteArray(m1CardHandler.readUid()));
                                                    if (GlobalDataHolder.getInstance().isSupportGetRfCardInfo()) {
                                                        TypeAInfoEntity typeAInfoEntity = new TypeAInfoEntity();
                                                        sdkCardReader.getRfCardInfo(typeAInfoEntity);
                                                        int atqaLen = 0;
                                                        if (typeAInfoEntity.getAtqa() != null)
                                                            atqaLen = typeAInfoEntity.getAtqa().length;
                                                        byte[] cardOther = new byte[atqaLen + 3];
                                                        System.arraycopy("00".getBytes(), 0, cardOther, 0, 2);
                                                        cardOther[2] = (byte) typeAInfoEntity.getAtqa().length;
                                                        if (atqaLen > 0)
                                                            System.arraycopy(typeAInfoEntity.getAtqa(), 0, cardOther, 3, typeAInfoEntity.getAtqa().length);
                                                        bundle.putByteArray(ICCSearchResult.CARDOTHER, cardOther);
                                                    }
                                                    log.debug("bundle M1SN:{},CARDOTHER:{}", bundle.get(ICCSearchResult.M1SN), bundle.get(ICCSearchResult.CARDOTHER));
                                                    listener.onSearchResult(ServiceResult.Success, bundle);
                                                    return;
                                                }
                                            }
                                            break;
                                        case IccCardType.FELICA:
                                            log.info("IccCardType {}", IccCardType.FELICA);
                                            if (cardInfoEntity.getCardExistslot() == CardSlotTypeEnum.RF) {
                                                if (cardInfoEntity.getRfCardType() == RfCardTypeEnum.FELICA) {
                                                    iccReaderHolder.setCardType(IccCardType.FELICA);
                                                    bundle.putString(ICCSearchResult.CARDTYPE, IccCardType.FELICA);
                                                    listener.onSearchResult(ServiceResult.Success, bundle);
                                                    return;
                                                }
                                            }
                                            break;
                                        //以下的卡只能通过复位接口去判断，不过有一些卡又没有复位功能，暂不处理了
                                        case IccCardType.AT24CXX:
                                            log.info("IccCardType {}", IccCardType.AT24CXX);
                                            iccReaderHolder.setCardType(IccCardType.AT24CXX);
                                            bundle.putString(ICCSearchResult.CARDTYPE, IccCardType.AT24CXX);
                                            listener.onSearchResult(ServiceResult.Success, bundle);
                                            return;
                                        case IccCardType.AT88SC102:
                                            log.info("IccCardType {}", IccCardType.AT88SC102);
                                            iccReaderHolder.setCardType(IccCardType.AT88SC102);
                                            bundle.putString(ICCSearchResult.CARDTYPE, IccCardType.AT88SC102);
                                            listener.onSearchResult(ServiceResult.Success, bundle);
                                            return;
                                        case IccCardType.AT88SC1604:
                                            log.info("IccCardType {}", IccCardType.AT88SC1604);
                                            iccReaderHolder.setCardType(IccCardType.AT88SC1604);
                                            bundle.putString(ICCSearchResult.CARDTYPE, IccCardType.AT88SC1604);
                                            listener.onSearchResult(ServiceResult.Success, bundle);
                                            return;
                                        case IccCardType.AT88SC1608:
                                            log.info("IccCardType {}", IccCardType.AT88SC1608);
                                            iccReaderHolder.setCardType(IccCardType.AT88SC1608);
                                            bundle.putString(ICCSearchResult.CARDTYPE, IccCardType.AT88SC1608);
                                            listener.onSearchResult(ServiceResult.Success, bundle);
                                            return;
                                        case IccCardType.SLE44X2:
                                            log.info("IccCardType {}", IccCardType.SLE44X2);
                                            iccReaderHolder.setCardType(IccCardType.SLE44X2);
                                            bundle.putString(ICCSearchResult.CARDTYPE, IccCardType.SLE44X2);
                                            listener.onSearchResult(ServiceResult.Success, bundle);
                                            return;
                                        case IccCardType.SLE44X8:
                                            log.info("IccCardType {}", IccCardType.SLE44X8);
                                            iccReaderHolder.setCardType(IccCardType.SLE44X8);
                                            bundle.putString(ICCSearchResult.CARDTYPE, IccCardType.SLE44X8);
                                            listener.onSearchResult(ServiceResult.Success, bundle);
                                            return;
                                    }
                                }
                                listener.onSearchResult(ServiceResult.IccCardReader_Read_CardType_Error, bundle);
                                break;
                            case SdkResult.TimeOut:
                                listener.onSearchResult(ServiceResult.TimeOut, bundle);
                                break;
                            default:
                                listener.onSearchResult(ServiceResult.IccCardReader_Other_Error, bundle);
                                break;
                        }
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onSwipeIncorrect() {

                }

                @Override
                public void onMultipleCards() {

                }
            });
            if (result == SdkResult.Success) {
                return ServiceResult.Success;
            } else {
                return ServiceResult.Fail;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ServiceResult.Fail;
        }
    }

    @Override
    public void stopSearch() throws RemoteException {
        log.info("call stopSearch");
        try {
            sdkCardReader.stopSearch();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean isCardExists() throws RemoteException {
        log.info("call isCardExists");
        log.info("isCardExists slotNo{}", slotNo + "");
        try {
            //交易完成后，会再调用这个接口，这时候emvhandler.onfinish里面已经下电了
            boolean s = sdkCardReader.isCardExist(CardUtils.slotConvert(slotNo));
            if (!s) {
                s = sdkCardReader.isCardExist(CardUtils.slotConvert(slotNo));
            }
            log.info("isCardExists {}", s + "");
            return s;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public boolean setupReaderConfig(Bundle bundle) throws RemoteException {
        log.info("call setupReaderConfig");
        if (bundle == null) return false;
        for (String str : bundle.keySet()) {
            if (bundle.get(str) instanceof byte[]) {
                log.debug("key {},value {}", str, ByteUtils.byteArray2HexString(bundle.getByteArray(str)));
            } else {
                log.debug("key {},value {}", str, bundle.get(str));
            }
        }
        return true;
    }
}
